package ConveyorBelt.Brain;

import java.util.ArrayList;
import java.util.Collections;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Vector2f;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.util.pathfinding.Path;
import org.newdawn.slick.util.pathfinding.Path.Step;

import ConveyorBelt.Actors.Switch;
import ConveyorBelt.Map.Map;

public class DummyBrain {
	public Map map;
	public Switch switchPoint;
	public Path path;
	public int currentStepIndex;
	public Vector2f currentPosition;
	public boolean cannotFindPath;
	public int turn = 0;
	/**
	 * Một bộ não của Dummt cần biết được vị trí và map mà dummy sẽ xuất hiện
	 * @param parent Map
	 * @param dummyPosition Vị trí của Dummy
	 */
	public DummyBrain(Map parent, Vector2f dummyPosition) {
		this.map = parent;
		this.currentPosition = dummyPosition;
		init();
	}
	/**
	 * Khởi tạo các giá trị ban đầu của một bộ não
	 */
    public void init() {
    	currentStepIndex = 0;
    	path = null;
    	cannotFindPath = false;
    }
    /**
     * Có thể sửa đổi hàm render để debug
     * @param bgs
     * @param g
     */
    public void render(BasicGameState bgs, Graphics g) {
    	//Không cần render gì hết
    }
    /**
     * Khi nào thì Brain sẽ cập nhật vị trí đến điểm khác, kiểm tra các điều kiện
     * @param delta
     */
    public void update(GameContainer gc, int delta) {
    	if(path == null) {
//    		System.out.println("Level: "+CurrentLevel.levelNumber);
    		lookAheadPath();
    	}
    	if(currentStepIndex >= path.getLength()) findAgain();
      	switchPoint.update(gc, delta);
    }
    
    public void findAgain() {
    	currentStepIndex = 0;
    	path = null;
    	lookAheadPath();
    }
    public void lookAheadPath() {
//    	System.out.println("TURN "+turn);
    	turn ++;
    	ArrayList<Path> lookAheadPaths = new ArrayList<Path>();
    	ArrayList<Path> followablePaths = new ArrayList<Path>();
    	
    	lookAheadPaths = findPathToSwitchs();
//    	System.out.println("Paths to Switch count: "+lookAheadPaths.size());
    	if(isAtSwitchPoint()) {
//       		System.out.println("Paths to Destination count: "+findPathToDestinations().size());
    		lookAheadPaths.addAll(findPathToDestinations());
//       		System.out.println("Size before:"+ lookAheadPaths.size());
    		for(int i=0; i<lookAheadPaths.size(); i++) {
    			if(lookAheadPaths.get(i) != null && isPathSameDirectionAsSwitch(lookAheadPaths.get(i), switchPoint)) {
    				followablePaths.add(lookAheadPaths.get(i));
    			}
    		}
//    		System.out.println("Size After: "+followablePaths.size());
    		path = getShorstestPath(followablePaths);
    	} else {
    		path = getShorstestPath(lookAheadPaths);
    	}
    }
    public Path getShorstestPath(ArrayList<Path> paths) {
    	ArrayList<Integer> pathLengths = new ArrayList<Integer>();
    	Path shortestPath = null;
    	Integer minLength;
	
		for(int i=0; i<paths.size(); i++) {
			pathLengths.add(paths.get(i).getLength());
//			System.out.println("Length: "+ paths.get(i).getLength());
		}
		minLength = Collections.min(pathLengths);
//		System.out.println("Min Length: "+minLength);
		for(int i=0; i<paths.size(); i++) 
			if(paths.get(i).getLength() == minLength) shortestPath = paths.get(i);
		
		return shortestPath;
    }
    public boolean isPathSameDirectionAsSwitch(Path path, Switch switchPoint) {
    	Step step = path.getStep(1);
    	int pathDirection = -1;
    	int tx = (int) (switchPoint.getX() - map.mapX)/32;
    	int ty = (int) (switchPoint.getY() - map.mapY)/32;
    	int dx = step.getX() - tx;
    	int dy = step.getY() - ty;
    	
//    	System.out.println("["+tx + "," +ty+"],["+step.getX() + "," + step.getY() +"]");
    	if(dx == 1 && dy == 0) pathDirection = Switch.direction.right.ordinal();
    	else if(dx == - 1 && dy == 0) pathDirection = Switch.direction.left.ordinal();
    	else if(dx == 0 && dy == 1) pathDirection = Switch.direction.down.ordinal();
    	else if(dx == 0 && dy == -1) pathDirection = Switch.direction.up.ordinal();
//    	System.out.print(pathDirection + "-" + switchPoint.currentDirection);
    	if(switchPoint.currentDirection == pathDirection) return true;    
//    	System.out.println(" Skip");
    	return false;
    }
    
    public boolean isAtSwitchPoint() {
    	for(int i=0; i<Map.switchEntities.size(); i++) {
    		switchPoint =(Switch) Map.switchEntities.get(i);
    		if(currentPosition.getX() == switchPoint.getX() && 
    				currentPosition.getY() == switchPoint.getY()) {
    			return true;
    		}
    	}
    	return false;
    }
    
    public ArrayList<Path> findPathToSwitchs() {
    	ArrayList<Path> paths = new ArrayList<Path>();
    	Path path = null;
    	for(int i=0; i<Map.switchEntities.size(); i++) {
    		path = map.getUpdatedPath(
    				(int) (currentPosition.getX() - map.mapX)/32, 
    				(int) (currentPosition.getY() - map.mapY)/32,
    				(int) (Map.switchEntities.get(i).getX() - map.mapX)/32,
    				(int) (Map.switchEntities.get(i).getY() - map.mapY)/32);
    		paths.add(path);
    	}
    	return paths;
    }
    
    public ArrayList<Path> findPathToDestinations() {
    	ArrayList<Path> paths = new ArrayList<Path>();
    	Path path = null;
    	for(int i=0; i<Map.destinationEntities.size(); i++) {
    		path = map.getUpdatedPath(
    				(int) (currentPosition.getX() - map.mapX)/32, 
    				(int) (currentPosition.getY() - map.mapY)/32,
    				(int) (Map.destinationEntities.get(i).getX() - map.mapX)/32,
    				(int) (Map.destinationEntities.get(i).getY() - map.mapY)/32);
    		paths.add(path);
    	}
    	return paths;
    }
    public Step getCurrentStep() {
    	return path.getStep(currentStepIndex);
    }
    public void goToNextStep(Vector2f position) {
    	currentStepIndex++;
    	this.currentPosition = position;
    	
    }
    public boolean isCannotFindPath() {
    	return cannotFindPath;
    }
    /**
     * Set lại tọa độ mới của Dummy
     * @param current Tọa độ mới của Dummy
     */
    public void setCurrent(Vector2f current) {
    	this.currentPosition = current;
    }
}